﻿using MapleLeaf.Pay.Trade;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Net;

namespace MapleLeaf.Pay.Pay {

    public class HongshPayTradeManager : ObservableCollection<HongshPayTrade> {

        public HongshPayTrade this[string tid, string rid] {
            get {
                HongshPayTrade result = !string.IsNullOrEmpty(tid) && TradeIndex.TryGetValue("T" + tid, out HongshPayTrade hongshPayTrade)
                    ? hongshPayTrade
                    : !string.IsNullOrEmpty(rid) && TradeIndex.TryGetValue("R" + rid, out hongshPayTrade) ? hongshPayTrade : null;
                return result;
            }
        }


        public void Print(HongshPayTrade t, int count = 1) {
            if (!string.IsNullOrEmpty(Config.PrinterName)) {
                using (EscPosPrinter escPosPrinter = new EscPosPrinter(Config.PrinterName)) {
                    for (int i = 0; i < count; i++) {
                        escPosPrinter.Init();
                        escPosPrinter.Justify(EscPosJustify.Center);
                        escPosPrinter.Size(EscPosTextSize.Height2);
                        escPosPrinter.WriteLine(Config.TradePrintTitle);
                        escPosPrinter.Size(EscPosTextSize.Nomal);
                        escPosPrinter.WriteLine("交易凭证");
                        escPosPrinter.WriteLine();
                        escPosPrinter.Justify(EscPosJustify.Left);
                        escPosPrinter.WriteLine("开始时间：" + t.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                        escPosPrinter.WriteLine("结束时间：" + t.UpdateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                        escPosPrinter.WriteLine("交易终端：" + t.TerminalId);
                        escPosPrinter.WriteLine("交易编号：" + t.TradeId);
                        escPosPrinter.WriteLine("交易金额：" + t.Amount.ToString("0.00"));
                        escPosPrinter.WriteLine("优惠金额：" + (t.Amount - t.ActualAmount).ToString("0.00"));
                        escPosPrinter.WriteLine("交易方式：" + t.Payway.ToString());
                        escPosPrinter.WriteLine("交易结果：" + t.State.ToString());
                        escPosPrinter.WriteLine("付 款 人：" + t.Payer);
                        escPosPrinter.WriteLine();
                        escPosPrinter.WriteLine(Config.TradePrintTail);
                        escPosPrinter.WriteLine();
                        escPosPrinter.WriteLine();
                        escPosPrinter.CutPaper();
                        escPosPrinter.Flush();
                    }
                }
            }
        }


        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
            if (e.Action == NotifyCollectionChangedAction.Add) {
                HongshPayTrade hongshPayTrade = e.NewItems[0] as HongshPayTrade;
                if (!string.IsNullOrEmpty(hongshPayTrade.TradeId)) {
                    TradeIndex["T" + hongshPayTrade.TradeId] = hongshPayTrade;
                }
                if (!string.IsNullOrEmpty(hongshPayTrade.ClientTradeId)) {
                    TradeIndex["R" + hongshPayTrade.ClientTradeId] = hongshPayTrade;
                }
                hongshPayTrade.PropertyChanged += OnTradePropertyChanged;
            }
            base.OnCollectionChanged(e);
        }


        private void OnTradePropertyChanged(object sender, PropertyChangedEventArgs e) {
            HongshPayTrade hongshPayTrade = sender as HongshPayTrade;
            if (e.PropertyName == "TradeId") {
                TradeIndex["T" + hongshPayTrade.TradeId] = hongshPayTrade;
            }
            else if (e.PropertyName == "ClientTradeId") {
                TradeIndex["R" + hongshPayTrade.ClientTradeId] = hongshPayTrade;
            }
            else if (e.PropertyName == "State" && hongshPayTrade.State == TradeState.成功) {
                try {
                    if (Config.IsTradeSoundPlay) {
                        string text = hongshPayTrade.Payway.ToString() + ((hongshPayTrade.Amount >= 0) ? "收款" : "退款") + TradePlayer.ConvertToChinese(((hongshPayTrade.Amount > 0) ? hongshPayTrade.Amount : (-hongshPayTrade.Amount)) / 100m);
                        TradePlayer.Speak(text);
                    }
                    Print(hongshPayTrade, Config.TradePrintCount);
                }
                catch {
                }
            }
        }


        public HongshPayClientConfig Config { get; }


        public HongshPayTradeManager(HongshPayClientConfig config) {
            TradeIndex = new Dictionary<string, HongshPayTrade>();
            Config = config;
        }

      
        private HongshPayApi GetApi(string ip) {
            bool flag;
            if (!string.IsNullOrEmpty(ip) && Config.Apis.TryGetValue(ip, out HongshPayApi hongshPayApi)) {
                flag = true;
            }
            else if (Config.Apis.TryGetValue("0.0.0.0", out hongshPayApi) && !string.IsNullOrEmpty(hongshPayApi.Id)) {
                string secret = hongshPayApi.Secret;
                flag = secret != null && secret.Length == 32;
            }
            else {
                flag = false;
            }
            return !flag ? throw new Exception("终端参数无效") : hongshPayApi;
        }


        public HongshPayTrade Execute(TradeAuthPaymentRequest req) {
            return Execute(GetApi(req.ClientIP), req);
        }

        
        private HongshPayTrade Execute(HongshPayApi api, TradeAuthPaymentRequest req) {
            string key = string.Join("-", new object[]
            {
                "A",
                req.Authcode,
                req.Amount,
                req.ClientIP,
                req.ClientTradeId
            });
            HongshPayTrade result;
            if (TradeIndex.TryGetValue(key, out HongshPayTrade hongshPayTrade) && DateTime.Now < hongshPayTrade.CreateTime.AddMinutes(2.0)) {
                result = hongshPayTrade.State == TradeState.成功
                    ? hongshPayTrade
                    : Execute(new TradePaymentQueryRequest {
                        TradeId = hongshPayTrade.TradeId,
                        ClientTradeId = hongshPayTrade.ClientTradeId
                    });
            }
            else {
                hongshPayTrade = new HongshPayTrade {
                    TerminalId = api.Id,
                    ClientIP = req.ClientIP,
                    ClientName = req.ClientName,
                    Amount = req.Amount
                };
                if (string.IsNullOrEmpty(req.ClientTradeId)) {
                    req.ClientTradeId = hongshPayTrade.CreateTime.ToString("yyMMddHHmmss") + req.Authcode.Substring(0, 2) + req.Authcode.Substring(req.Authcode.Length - 4);
                }
                hongshPayTrade.ClientTradeId = req.ClientTradeId;
                Insert(0, TradeIndex[key] = hongshPayTrade);
                try {
                    TradeCompleteResult tradeCompleteResult = api.Execute(req);
                    if (string.IsNullOrEmpty(hongshPayTrade.TradeId)) {
                        hongshPayTrade.TradeId = tradeCompleteResult.TradeId;
                    }
                    hongshPayTrade.ActualAmount = tradeCompleteResult.ActualAmount;
                    hongshPayTrade.Payway = tradeCompleteResult.Payway;
                    hongshPayTrade.Payer = tradeCompleteResult.Payer;
                    hongshPayTrade.StateDescript = tradeCompleteResult.StateDescript;
                    hongshPayTrade.CreateTime = TimeStamp.GetDateTime(tradeCompleteResult.CreateTimes);
                    hongshPayTrade.UpdateTime = TimeStamp.GetDateTime(tradeCompleteResult.UpdateTimes);
                    hongshPayTrade.State = tradeCompleteResult.State;
                }
                catch (Exception ex) {
                    if (!(ex is WebException) || !(ex as WebException).IsRecvingException()) {
                        hongshPayTrade.State = TradeState.失败;
                    }
                    hongshPayTrade.UpdateTime = DateTime.Now;
                    hongshPayTrade.StateDescript = ex.Message;
                }
                result = hongshPayTrade;
            }
            return result;
        }

        
        public HongshPayTrade Execute(TradePaymentQueryRequest req) {
            return Execute(GetApi(req.ClientIP), req);
        }

       
        private HongshPayTrade Execute(HongshPayApi api, TradePaymentQueryRequest req) {
            HongshPayTrade hongshPayTrade = this[req.TradeId, req.ClientTradeId];
            if (hongshPayTrade == null) {
                hongshPayTrade = new HongshPayTrade {
                    TerminalId = api.Id,
                    TradeId = req.TradeId,
                    ClientIP = req.ClientIP,
                    ClientName = req.ClientName,
                    ClientTradeId = req.ClientTradeId
                };
                Insert(0, hongshPayTrade);
            }
            else if (string.IsNullOrEmpty(req.TradeId)) {
                req.TradeId = hongshPayTrade.TradeId;
            }
            try {
                TradeCompleteResult tradeCompleteResult = api.Execute(req);
                if (string.IsNullOrEmpty(hongshPayTrade.TradeId)) {
                    hongshPayTrade.TradeId = tradeCompleteResult.TradeId;
                }
                if (string.IsNullOrEmpty(hongshPayTrade.ClientTradeId)) {
                    hongshPayTrade.ClientTradeId = tradeCompleteResult.ClientTradeId;
                }
                if (hongshPayTrade.Amount == 0) {
                    hongshPayTrade.Amount = tradeCompleteResult.Amount;
                }
                hongshPayTrade.ActualAmount = tradeCompleteResult.ActualAmount;
                hongshPayTrade.Payway = tradeCompleteResult.Payway;
                hongshPayTrade.Payer = tradeCompleteResult.Payer;
                hongshPayTrade.StateDescript = tradeCompleteResult.StateDescript;
                hongshPayTrade.CreateTime = TimeStamp.GetDateTime(tradeCompleteResult.CreateTimes);
                hongshPayTrade.UpdateTime = TimeStamp.GetDateTime(tradeCompleteResult.UpdateTimes);
                hongshPayTrade.State = tradeCompleteResult.State;
            }
            catch (Exception ex) {
                hongshPayTrade.UpdateTime = DateTime.Now;
                hongshPayTrade.StateDescript = ex.Message;
                throw ex;
            }
            return hongshPayTrade;
        }

      
        public HongshPayTrade Execute(TradeRefundQueryRequest req) {
            return Execute(GetApi(req.ClientIP), req);
        }

     
        private HongshPayTrade Execute(HongshPayApi api, TradeRefundQueryRequest req) {
            HongshPayTrade hongshPayTrade = this[req.TradeId, req.ClientTradeId];
            if (hongshPayTrade == null) {
                hongshPayTrade = new HongshPayTrade {
                    TerminalId = api.Id,
                    TradeId = req.TradeId,
                    ClientTradeId = req.ClientTradeId,
                    ClientIP = req.ClientIP,
                    ClientName = req.ClientName
                };
                Insert(0, hongshPayTrade);
            }
            else if (string.IsNullOrEmpty(req.TradeId)) {
                req.TradeId = hongshPayTrade.TradeId;
            }
            try {
                TradeCompleteResult tradeCompleteResult = api.Execute(req);
                if (string.IsNullOrEmpty(hongshPayTrade.TradeId)) {
                    hongshPayTrade.TradeId = tradeCompleteResult.TradeId;
                }
                if (string.IsNullOrEmpty(hongshPayTrade.ClientTradeId)) {
                    hongshPayTrade.ClientTradeId = tradeCompleteResult.ClientTradeId;
                }
                if (hongshPayTrade.Amount == 0) {
                    hongshPayTrade.Amount = tradeCompleteResult.Amount;
                }
                hongshPayTrade.ActualAmount = tradeCompleteResult.ActualAmount;
                hongshPayTrade.Payway = tradeCompleteResult.Payway;
                hongshPayTrade.Payer = tradeCompleteResult.Payer;
                hongshPayTrade.State = tradeCompleteResult.State;
                hongshPayTrade.StateDescript = tradeCompleteResult.StateDescript;
                hongshPayTrade.CreateTime = TimeStamp.GetDateTime(tradeCompleteResult.CreateTimes);
                hongshPayTrade.UpdateTime = TimeStamp.GetDateTime(tradeCompleteResult.UpdateTimes);
            }
            catch (Exception ex) {
                hongshPayTrade.UpdateTime = DateTime.Now;
                hongshPayTrade.StateDescript = ex.Message;
            }
            return hongshPayTrade;
        }

        public HongshPayTrade Execute(TradeCloseRequest req) {
            return Execute(GetApi(req.ClientIP), req);
        }

      
        private HongshPayTrade Execute(HongshPayApi api, TradeCloseRequest req) {
            HongshPayTrade hongshPayTrade = this[req.TradeId, req.ClientTradeId];
            try {
                TradeResult tradeResult = api.Execute(req);
                if (!string.IsNullOrEmpty(req.TradeId)) {
                    hongshPayTrade.TradeId = tradeResult.TradeId;
                }
                hongshPayTrade.State = tradeResult.State;
                hongshPayTrade.StateDescript = tradeResult.StateDescript;
            }
            catch (Exception ex) {
                hongshPayTrade.UpdateTime = DateTime.Now;
                hongshPayTrade.StateDescript = ex.Message;
            }
            return hongshPayTrade;
        }


        public HongshPayTrade Execute(TradeRefundRequest req) {
            return Execute(GetApi(req.ClientIP), req);
        }

     
        private HongshPayTrade Execute(HongshPayApi api, TradeRefundRequest req) {
            HongshPayTrade hongshPayTrade = new HongshPayTrade {
                TerminalId = api.Id,
                ClientTradeId = req.ClientRefundTradeId,
                ClientIP = req.ClientIP,
                ClientName = req.ClientName,
                Amount = -req.RefundAmount
            };
            Insert(0, hongshPayTrade);
            try {
                TradeCompleteResult tradeCompleteResult = api.Execute(req);
                if (!string.IsNullOrEmpty(hongshPayTrade.TradeId)) {
                    hongshPayTrade.TradeId = tradeCompleteResult.TradeId;
                }
                hongshPayTrade.ActualAmount = -tradeCompleteResult.ActualAmount;
                hongshPayTrade.Payway = tradeCompleteResult.Payway;
                hongshPayTrade.Payer = tradeCompleteResult.Payer;
                hongshPayTrade.StateDescript = tradeCompleteResult.StateDescript;
                hongshPayTrade.CreateTime = TimeStamp.GetDateTime(tradeCompleteResult.CreateTimes);
                hongshPayTrade.UpdateTime = TimeStamp.GetDateTime(tradeCompleteResult.UpdateTimes);
                hongshPayTrade.State = tradeCompleteResult.State;
            }
            catch (Exception ex) {
                if (!(ex is WebException) || !(ex as WebException).IsRecvingException()) {
                    hongshPayTrade.State = TradeState.失败;
                }
                hongshPayTrade.UpdateTime = DateTime.Now;
                hongshPayTrade.StateDescript = ex.Message;
            }
            return hongshPayTrade;
        }

     
        private readonly Dictionary<string, HongshPayTrade> TradeIndex;
    }
}
